/**
 * Axios 请求封装
 *
 */

import { AxiosInstance, AxiosRequestConfig, AxiosResponse, AxiosError } from 'axios';
import { message } from 'antd';
import defaultAgent from './Agent';
import Utils from '../Utils';
import { MessageApi } from 'antd/lib/message';

enum HttpMethods {
  GET = 'get',
  POST = 'post',
  PUT = 'put',
  DELETE = 'delete',
  PATCH = 'patch'
}

const CodeMessage: [number, string][] = [
  [400, '请求错误, 请重新尝试'],
  [401, '由于长时间没有操作, 请重新登录'],
  [403, '无访问权限'],
  [404, '请求错误, 请重新尝试'],
  [500, '服务器错误, 请稍后重试'],
  [502, '网关错误, 请稍后重试'],
  [503, '服务不可用, 服务器暂时过载或处于维护状态, 请稍后重试'],
  [504, '服务器响应超时, 请重试']
];

interface ResultNotice {
  duration?: number;
  content: string;
}

interface BaseConfig {
  url: string;
  params?: Object;
  successNotice?: ResultNotice;
  errorNotice?: ResultNotice;
}

interface PostConfig extends BaseConfig {
  data: any;
}

export class BaseAPI {
  private duration: number = 3;
  private codeMessage: Map<number, string> = new Map(CodeMessage);

  public constructor(public agent: AxiosInstance = defaultAgent, public notice: MessageApi = message) {}

  public async get<T>(config: BaseConfig, extra: AxiosRequestConfig = {}): Promise<T> {
    return this.request<T>(HttpMethods.GET, config, extra);
  }

  public async post<T>(config: PostConfig, extra: AxiosRequestConfig = {}): Promise<T> {
    return this.request(HttpMethods.POST, config, extra);
  }

  public async put<T>(config: PostConfig, extra: AxiosRequestConfig = {}): Promise<T> {
    return this.request(HttpMethods.PUT, config, extra);
  }

  public async patch<T>(config: PostConfig, extra: AxiosRequestConfig = {}): Promise<T> {
    return this.request(HttpMethods.PATCH, config, extra);
  }

  public async delete<T>(config: BaseConfig, extra: AxiosRequestConfig = {}): Promise<T> {
    return this.request(HttpMethods.DELETE, config, extra);
  }

  private async request<T>(method: HttpMethods, config: BaseConfig | PostConfig, extra: AxiosRequestConfig = {}): Promise<T> {
    let requestConfig: AxiosRequestConfig = {
      url: config.url,
      method,
      params: { ...config.params },
      ...extra
    };

    if (method === HttpMethods.POST || method === HttpMethods.PUT || method === HttpMethods.PATCH) {
      requestConfig.data = (config as PostConfig).data;
    }

    return this.agent(requestConfig)
      .then((response: AxiosResponse) => {
        // 请求成功
        if (config.successNotice && config.successNotice.content) {
          const { content, duration } = config.successNotice;
          this.notice.success(content, duration || this.duration);
        }
        // 保存token值
        const token = response.headers['access-token'];
        if (token) Utils.session('user.token', token);
        return response.data;
      })
      .catch((error: AxiosError) => {
        // 请求失败
        const { status } = error.response!;
        const content = config.errorNotice && config.errorNotice.content;
        const duration = config.errorNotice && config.errorNotice.duration;
        this.notice.error(content || this.codeMessage.get(status), duration || this.duration);
        throw error;
      });
  }
}

export default new BaseAPI();
